﻿Imports VBF.ParserCombinator
Imports System.Console
Module Module1

    Sub Main()

        Test3()
    End Sub

    Function SampleSemanticRule(ByVal context As VBF.ParserCombinator.ParserContext) As Object
        Dim x = context.CurrentProduction.Sequence.Count

        Dim y As New List(Of Object)

        For i = 0 To x - 1
            y.Add(context.GetSymbolResult(i))
        Next



        Return context.CurrentProduction
    End Function

    Sub Test3()
        Dim s As New StringScanner
        s.Source = "1+5*6+7*(8+9)+2"

        Dim m As New ProductionManager
        Dim num = m.DefineTerminal("number")
        Dim plus = m.DefineTerminal("+")
        Dim leftph = m.DefineTerminal("(")
        Dim rightph = m.DefineTerminal(")")
        Dim star = m.DefineTerminal("*")

        s.EOSTerminal = m.EndOfFile

        s.RegisterTerminal("1"c, num)
        s.RegisterTerminal("2"c, num)
        s.RegisterTerminal("3"c, num)
        s.RegisterTerminal("4"c, num)
        s.RegisterTerminal("5"c, num)
        s.RegisterTerminal("6"c, num)
        s.RegisterTerminal("7"c, num)
        s.RegisterTerminal("8"c, num)
        s.RegisterTerminal("9"c, num)
        s.RegisterTerminal("0"c, num)
        s.RegisterTerminal("+"c, plus)
        s.RegisterTerminal("*"c, star)
        s.RegisterTerminal("("c, leftph)
        s.RegisterTerminal(")"c, rightph)

        Dim F = m.DefineNonTerminal("F")
        Dim E = m.DefineNonTerminal("E")
        Dim T = m.DefineNonTerminal("T")

        E.Produces(E, plus, T).SemanticRule = AddressOf SampleSemanticRule
        E.Produces(T).SemanticRule = AddressOf SampleSemanticRule
        T.Produces(T, star, F).SemanticRule = AddressOf SampleSemanticRule
        T.Produces(F).SemanticRule = AddressOf SampleSemanticRule
        F.Produces(num).SemanticRule = AddressOf SampleSemanticRule
        F.Produces(leftph, E, rightph).SemanticRule = AddressOf SampleSemanticRule

        m.SetRootSymbol(E)
        m.GenerateTransitionTable()
        Dim amb = m.IdentifyActions()

        m.CalculateParserContext()

        Stop

        Dim p As New ParserDriver(m, s)

        p.Start()
    End Sub

    Sub test1()
        Dim m As New ProductionManager()
        '    Dim id, num, print, semic, comma, plus, assign, leftp, rightp As DebugTerminal

        Dim S = m.DefineNonTerminal("S")
        Dim E = m.DefineNonTerminal("E")
        Dim L = m.DefineNonTerminal("L")

        Dim id = m.DefineTerminal("id")
        Dim num = m.DefineTerminal("num")
        Dim print = m.DefineTerminal("print")
        Dim semic = m.DefineTerminal(";")
        Dim comma = m.DefineTerminal(",")
        Dim plus = m.DefineTerminal("+")
        Dim assign = m.DefineTerminal(":=")
        Dim leftp = m.DefineTerminal("(")
        Dim rightp = m.DefineTerminal(")")

        'S → S; S 
        'S → id := E 
        'S → print (L)
        'E → id
        'E → num
        'E → E + E 
        'E → (S, E)
        'L → E 
        'L → L, E 


        S.Produces(S, semic, S)
        S.Produces(id, assign, E)
        S.Produces(print, leftp, L, rightp)
        E.Produces(id)
        E.Produces(num)
        E.Produces(E, plus, E)
        E.Produces(leftp, S, comma, E, rightp)
        L.Produces(E)
        L.Produces(L, comma, E)

        '    ''m.CalculateNullableAndFirst()

        '    ''Dim Z_Item = New LR1Item(S2.Productions(0), 0, New Any)
        '    ''Dim closure = LR1Item.GetClosure(New LR1Item() {Z_Item})

        '    ''Dim gotoV = LR1Item.GotoSymbol(closure, V)
        '    ''Dim gotoEq = LR1Item.GotoSymbol(gotoV, eq)
        '    ''Dim gotoStar = LR1Item.GotoSymbol(gotoEq, star)

        m.SetRootSymbol(S)
        m.GenerateTransitionTable()
        Dim amb = m.IdentifyActions()
        Stop
    End Sub

    Sub Test2()
        Dim m As New ProductionManager


        Dim E = m.DefineNonTerminal("E")
        Dim T = m.DefineNonTerminal("T")
        Dim F = m.DefineNonTerminal("F")

        Dim plus = m.DefineTerminal("+")
        Dim number = m.DefineTerminal("number")
        Dim leftph = m.DefineTerminal("(")
        Dim rightph = m.DefineTerminal(")")
        Dim star = m.DefineTerminal("*")

        E.Produces(E, plus, T)
        E.Produces(T)
        T.Produces(T, star, F)
        T.Produces(F)
        F.Produces(number)
        F.Produces(leftph, E, rightph)

        'm.AddTerminals(plus, number, leftph, rightph, star)
        'm.AddNonTerminals(E, T, F)

        m.SetRootSymbol(E)
        m.GenerateTransitionTable()

        Dim amb = m.IdentifyActions()
        Stop
    End Sub

    'Sub Test3()
    '    Dim E As DebugProductionVar
    '    Dim plus, number, leftph, rightph, star As DebugTerminal

    '    E = "E"

    '    plus = "+"
    '    number = "number"
    '    leftph = "("
    '    rightph = ")"
    '    star = "*"

    '    E.Produces(E, plus, E)
    '    E.Produces(E, star, E)
    '    E.Produces(number)
    '    E.Produces(leftph, E, rightph)

    '    'Dim m As New ProductionManager
    '    'm.AddTerminals(plus, number, leftph, rightph, star)
    '    'm.AddNonTerminals(E)

    '    'm.SetRootSymbol(E)
    '    'm.GenerateTransitionTable()

    '    'Dim amb = m.CheckConflicts()
    '    Stop
    'End Sub
End Module


Class CharToken
    Implements IToken

    Public Value As Char

    Private m_isEOF As Boolean
    Public ReadOnly Property IsEndOfFile() As Boolean Implements VBF.ParserCombinator.IToken.IsEndOfFile
        Get
            Return m_isEOF
        End Get
    End Property


    Private m_span As SourceSpan
    Public ReadOnly Property Span() As VBF.ParserCombinator.SourceSpan Implements VBF.ParserCombinator.IToken.Span
        Get
            Return m_span
        End Get
    End Property

    Private m_terminal As Terminal
    Public ReadOnly Property Terminal() As VBF.ParserCombinator.Terminal Implements VBF.ParserCombinator.IToken.Terminal
        Get
            Return m_terminal
        End Get
    End Property

    Public Sub New(ByVal span As SourceSpan, ByVal terminal As Terminal)
        m_isEOF = False
        m_span = span
        m_terminal = terminal
    End Sub

    Public Sub New(ByVal span As SourceSpan, ByVal terminal As Terminal, ByVal isEOF As Boolean)
        m_isEOF = isEOF
        m_span = span
        m_terminal = terminal
    End Sub

End Class

Class StringScanner
    Implements IScanner

    Public Source As String
    Public Cursor As Integer
    Public PeekChar As Char

    Public Dict As Dictionary(Of Char, Terminal)
    Public EOSTerminal As Terminal

    Public Sub RegisterTerminal(ByVal c As Char, ByVal t As Terminal)
        Dict(c) = t
    End Sub

    Sub New()
        Dict = New Dictionary(Of Char, Terminal)
    End Sub

    Public ReadOnly Property CurrentLocation() As VBF.ParserCombinator.Location Implements IScanner.CurrentLocation
        Get
            Return New Location(Cursor, 0, 0)
        End Get
    End Property

    Public Function Peek() As VBF.ParserCombinator.IToken Implements IScanner.Peek
        Dim tempToken = Read()
        If Not tempToken.IsEndOfFile Then Cursor -= 1

        Return tempToken
    End Function

    Public Function PeekAhead() As VBF.ParserCombinator.IToken Implements IScanner.PeekAhead
        Dim tempToken = Read()
        If tempToken.IsEndOfFile Then Return tempToken

        Dim tempToken2 = Read()
        If tempToken2.IsEndOfFile Then
            Cursor -= 1
            Return tempToken2
        End If

        Cursor -= 2
        Return tempToken2
    End Function

    Public Function Read() As VBF.ParserCombinator.IToken Implements IScanner.Read
        If Cursor >= Source.Length Then
            Return New CharToken(New SourceSpan(New Location(Cursor - 1, 0, 0), New Location(Cursor - 1, 0, 0)), EOSTerminal, True)
        Else
            PeekChar = Source(Cursor)
            Cursor += 1

            Return New CharToken(New SourceSpan(New Location(Cursor - 1, 0, 0), New Location(Cursor - 1, 0, 0)), Dict(PeekChar)) With {.Value = PeekChar}
        End If
    End Function

End Class


'<DebuggerDisplay("Terminal({m_char})")> _
'Class DebugTerminal
'    Inherits Terminal

'    Private m_char As String

'    Public Sub New(ByVal c As String)
'        m_char = c
'    End Sub

'    Public Shared Widening Operator CType(ByVal c As String) As DebugTerminal
'        Return New DebugTerminal(c)
'    End Operator

'    Public Overrides Function ToString() As String
'        Return m_char
'    End Function
'End Class

'<DebuggerDisplay("Production({m_char})")> _
'Class DebugProductionVar
'    Inherits NonTerminal

'    Private m_char As String
'    Public Sub New(ByVal c As String)
'        m_char = c
'    End Sub

'    Public Shared Widening Operator CType(ByVal c As String) As DebugProductionVar
'        Return New DebugProductionVar(c)
'    End Operator

'    Public Overrides Function ToString() As String
'        Return m_char
'    End Function
'End Class